iT邦幫忙

2025 iThome 鐵人賽

DAY 22
0
Cloud Native

EKS in Practice:IaC × GitOps 實戰 30 天系列 第 22

[Day 22] 安全通道:Transit Gateway 與 GitLab Runner 串接的秘密

  • 分享至 

  • xImage
  •  

昨天 (Day 21) 的 CI/CD script 中有一個步驟是把 image 推送到 ECR,針對這個步驟我們可以來聊一下 ECR 授權的機制

目前常見有兩種主要的方案:

  • User Access Key 驗證:直接使用 AWS IAM User 的 Access Key 和 Secret Key 進行認證。
  • IAM Role 驗證:透過 AssumeRole 機制,讓執行環境臨時獲取權限。

當前,我們採用的是第一種方式 —— User Access Key。這是因為我們的 GitLab Runner 是公司集團共用的資源,我們並不擁有其執行環境的完全控制權,因此只好將 AWS 憑證以環境變數的方式存放在 GitLab CI/CD 變數中。

但這樣長期來說存在著明顯的風險:

  • 金鑰洩漏風險:一旦變數被誤打到 log 或者被人誤用,整個帳號可能會被全面入侵。
  • 權限控管困難:IAM User 的金鑰具備長期存活的特性,很難落實最小權限原則。

因此,我們最終決定 部署自己的 GitLab Runner,並且透過 Transit Gateway 打通網路,讓 Runner 可以直接透過 IAM Role 與 AWS 資源互動,徹底擺脫長期金鑰的依賴。


Transit Gateway 打通流程

我們的需求其實很單純:

  • GitLab Runner 會直接跑在 EKS Cluster 裡,也就是跟 EKS 在同一個 VPC。
  • 我們只需要讓 EKS VPC ↔ GitLab VPC 能互通,就能讓 Runner 存取 GitLab 服務。

之所以要使用 Transit Gateway (TGW),並不是因為我們有太多 VPC,而是因為 GitLab VPC 是由另一個單位管理,而該單位必須跟許多外部單位串接,他們統一要求透過 TGW 來進行連線。換句話說,TGW 在這裡就是一個「必須遵守的規範」,我們要配合使用。

Transit Gateway 元件簡介

理解 TGW 的幾個核心元件,有助於看懂架構:

  • Transit Gateway (TGW):中央交換機,所有 VPC 透過 Attachment 掛上後就能互通。
  • VPC Attachment:每個要連到 TGW 的 VPC、或者相連的 TGW,都需要建立一個 Attachment。
    • 基本上 Attachment 有四種(VPC / VPN / Peering / Connect),我們只會用到 VPC 和 Peering 這兩種 type 而已。
  • Route Table:TGW 與 VPC 雙方都要有對應的路由設定,才能讓流量導進導出。
  • Security Group (SG):最後還要放行對方的 CIDR,否則流量會被防火牆擋住。

以下示意圖展示我們的情境:EKS VPC 與 GitLab VPC 之間透過 TGW 打通,其中 EKS VPC 內部就跑著我們的 Runner。

https://ithelp.ithome.com.tw/upload/images/20250922/20119667viuwPazS3y.png

要注意上圖強調的是 TGW 端的設定,因此除了 TGW Route Table,VPC 自己的 Route Table 和 Security Group 也需要更新,流量才會順利通過。

實作步驟

  1. 建立獨立的 Transit Gateway

    resource "aws_ec2_transit_gateway" "this" {
      amazon_side_asn = XXXXX
      tags = {
        "Name" = "example-internal-tgw"
      }
    }
    
  2. 與集團的 Transit Gateway 進行 Peering。這段的 attachment 因為是由對方發起的請求,因此我們採用 console 點選的方式與對方對接。結果如下圖:

    https://ithelp.ithome.com.tw/upload/images/20250922/20119667gBT7bkWwAJ.jpg

  3. 在 Transit Gateway Route Table 新增對內部網段的路由

    resource "aws_ec2_transit_gateway_route" "to_internal" {
      for_each = toset(var.corporate_cidrs)
    
      destination_cidr_block         = each.value
      ### 這邊會指向前一步建立的 attachment
      ### 因為是 console 建立的,所以這邊用 data 來撈
      transit_gateway_attachment_id  = data.aws_ec2_transit_gateway_peering_attachment.this.id
      ### 會指向前一步 attachment 預設的 route table,一樣用 data 撈回
      transit_gateway_route_table_id = data.aws_ec2_transit_gateway_route_table.this.id
    }
    
  4. 建立 VPC Attachment

    resource "aws_ec2_transit_gateway_vpc_attachment" "internal" {
    	### 把 VPC attachment 貼到我們的 private subnet 上
      subnet_ids         = data.aws_subnets.internal_private_subnets.ids
      transit_gateway_id = aws_ec2_transit_gateway.this.id
      vpc_id             = data.aws_vpc.internal.id
    }
    
  5. 在 VPC Route Table 新增回程路由

    resource "aws_route" "internal_private" {
      for_each = toset(var.corporate_cidrs)
    
    	### 一樣是貼回第二步建立的 attachment 預設的 route table 中
      route_table_id         = data.aws_route_table.internal_private.id
      destination_cidr_block = each.value
      ### 藉由我們建立的 TGW 來進行路由
      transit_gateway_id     = aws_ec2_transit_gateway.this.id
    }
    
  6. 更新 Security Group

    resource "aws_vpc_security_group_ingress_rule" "internal_node_sg" {
      for_each = toset(var.corporate_cidrs)
    
      description       = "Allow internal VPC communication"
      security_group_id = data.aws_security_group.internal_node_sg.id
      cidr_ipv4         = each.value
      ip_protocol       = "tcp"
      from_port         = 0
      to_port           = 65535
    }
    

測試連線

  1. 進入 Argo CD Repo Server Pod

    kubectl exec -it deploy/argocd-repo-server -n argocd -- sh
    
  2. 嘗試 git clone 內部 Repo

    cd /helm-working-dir/
    git clone [internal-repo]
    
  3. 如果能順利 clone,而不是 timeout,就表示 TGW 已經打通。

  4. 測試完成後,把 SSH Known Hosts 加入 Argo CD,並把 Repo 設定改為 gitlab.internal.com


GitLab Runner 部署 (ApplicationSet 架構)

在網路打通後,我們就能在 EKS 內部部署自有 Runner。我們採用的方式並不是單純安裝 Helm Release,而是延續前幾天的 ApplicationSet 架構,讓多架構 Runner 能自動生成對應的 Deployment。

ApplicationSet 設計

透過 Git Generator,我們會讀取 internal/ 目錄下的檔案,裡面定義了不同架構的 Runner(例如 arm.yamlx86.yaml)。ApplicationSet 會依據這些檔案自動建立 Runner 的 Application。

https://ithelp.ithome.com.tw/upload/images/20250922/20119667OEYjK2tbLh.jpg

Runner 設定

在每個架構的 values 檔案裡,我們會設定:

  • ServiceAccount Annotation:掛上 IAM Role,讓 Runner 使用 IRSA 存取 AWS。
  • NodeSelector / Toleration:確保 Runner 跑在對應的 node(arm/x86)。
  • Helper Image:指定對應架構的 helper image,確保 CI/CD pipeline 正常運作。

例如 arm.yaml 的片段如下:

gitlab-runner:
  serviceAccount:
    annotations:
      eks.amazonaws.com/role-arn: arn:aws:iam::<account-id>:role/gitlab-runner-arm
  nodeSelector:
    usage: runner-arm
  tolerations:
    - key: RunnerArmOnly
      operator: Exists
  serviceAccount:
    name: gitlab-runner-arm
  runners:
    config: |
      [[runners]]
        [runners.kubernetes]
          service_account = "gitlab-runner-arm"
          helper_image = "registry.gitlab.com/gitlab-org/gitlab-runner/gitlab-runner-helper:arm64-${CI_RUNNER_REVISION}"

https://ithelp.ithome.com.tw/upload/images/20250922/20119667AhNcvNlnYm.jpg

這樣,我們就能在同一個 ApplicationSet 中,同時管理 arm 與 x86 的 Runner,不需要手動維護多個 Helm Release,而是透過 Git 檔案驅動,實現多架構 Runner 的自動化管理。


IAM Role 與 ECR 驗證

完成 Runner 部署後,下一步就是讓它們透過 IAM Role for Service Account (IRSA) 與 ECR 溝通:

  • 避免硬編碼金鑰。
  • 使用臨時憑證,自動過期。
  • 依照架構或用途分別設置最小權限 IAM Policy。

另外,在多帳號的情境下,我們也必須考慮權限邊界的設計:

  • GitLab Runner 會先綁定一個 GitLab Runner Role
  • 如果之後我們要在其他帳號裡使用同一個 Runner,做法是讓 GitLab Runner Role 具備 sts:AssumeRole 權限,可以切換成對應帳號的 專案 Runner Role
  • 開發者只需要在自己的 專案 Runner Role 中設置實際需要的權限(例如存取某個 ECR Repository 或 S3 Bucket),就能完成最小權限管理。

這樣一來,就能避免 GitLab Runner Role 本身權限過大的問題,同時也把跨帳號的責任切分清楚。


結語與明日預告

今天,我們完成了 Transit Gateway 與 GitLab Runner 部署

  • Transit Gateway 打通了多個 VPC,讓內部服務可以互通。
  • GitLab Runner 透過 ApplicationSet 架構部署,並針對 arm 與 x86 分別設定 Helper Image 與 IAM Role。

明天 (Day 23),我們會介紹 CRI / CNI / CSI 這三個 Kubernetes 基本介面,這些介面是理解 Kubernetes 底層運作的關鍵,也為後續 Day 24/25 的 K8s Networking,以及 Day 26-28 的 Service Mesh 與 Cilium 做好準備! 🚀


上一篇
[Day 21] GitOps 的最後一哩路:CI/CD Pipeline 與 Image 自動更新
系列文
EKS in Practice:IaC × GitOps 實戰 30 天22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言